﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

using DashFire;
using UnityEngine;
using UnityEditor;
using System.Security.Cryptography;

namespace DashFire.Assetbundle
{
  internal class ExportRes_Sheet
  {
    internal static string s_SheetListFile = "list.txt";
    internal static string s_SheetContentFile = "sheet.txt";
    internal static string s_SheetCachePath = "DataFile/";
    internal static string[] s_SheetPattern = new string[] { ".txt", ".map", ".dsl", ".obs" };
    internal static string s_SheetName = "sheet";
    internal const string s_ResSheetZipFormat = "sheet{0}.ab";
    internal const string s_ResSheetZipPrefix = "sheet";

    static ExportResInfo s_SheetData = null;
    static List<string> s_SheetListContent = new List<string>();

    internal static bool ExportClientResources()
    {
      // 1.Init Environment
      if (!InitEnvironment()) {
        ExportConfig.Log("ExportClientResources.InitEnvironment failed:");
        return false;
      }

      // 2.Generate ExportResInfo
      GenResInfo(false);
      string sheetListFile = ExportConfig.PathCombine("Assets/StreamingAssets", s_SheetListFile);

      // 3.Collect sheetFile to s_SheetListContent
      string[] tSheetListContent = File.ReadAllLines(sheetListFile);
      foreach (string sheetFile in tSheetListContent) {
        if (!string.IsNullOrEmpty(sheetFile.Trim()) && ExportConfig.IsEndWith(sheetFile, s_SheetPattern)) {
          string sheetPathCheck = ExportConfig.PathCombine("Assets/StreamingAssets", sheetFile);
          if (File.Exists(sheetPathCheck)) {
            s_SheetListContent.Add(sheetFile);
          }
        } else {
          continue;
        }
      }

      // 4.Serialize sheet.txt
      if (s_SheetListContent != null && s_SheetListContent.Count > 0) {
        s_SheetData.m_IsNeedBuild = true;
        string sheetContentFile = ExportConfig.PathCombine("Assets/StreamingAssets", s_SheetContentFile);
        s_SheetListContent.Insert(0, s_SheetListContent.Count.ToString());
        File.WriteAllLines(sheetContentFile, s_SheetListContent.ToArray(), Encoding.UTF8);
        AssetDatabase.Refresh();

        // 5.Export all sheet files
        if (!Export()) {
          ExportConfig.Log("ExportClientResources.s_SheetListContent failed:");
          return false;
        }
      }

      ExportConfig.Log("ExportRes_Sheet.ExportClientResources Success");
      return true;
    }
    internal static bool ExportDiffResources()
    {
      // 1.Init Environment
      if (!InitEnvironment()) {
        ExportConfig.Log("ExportDiffResources.InitEnvironment failed:");
        return false;
      }

      // 2.Collect sheetFile to s_SheetListContent
      GenResInfo(true);
      foreach (string sheetFile in ExportConfig.s_DiffContent) {
        if (!string.IsNullOrEmpty(sheetFile.Trim()) && ExportConfig.IsEndWith(sheetFile, s_SheetPattern)
          && (sheetFile.ToLower().StartsWith("client/")
              || sheetFile.ToLower().StartsWith("public/"))) {
          string sheetPathCheck = ExportConfig.PathCombine("Assets/StreamingAssets", sheetFile);
          if (File.Exists(sheetPathCheck)) {
            s_SheetListContent.Add(sheetFile);
            ExportConfig.Log("CheckDiffFile NeedBuild:{0} DependGuid:{1}", sheetPathCheck, sheetFile);
          }
        }
      }

      // 3.Serialize sheet.txt
      if (s_SheetListContent != null && s_SheetListContent.Count > 0) {
        s_SheetData.m_IsNeedBuild = true;

        string sheetContentFile = ExportConfig.PathCombine("Assets/StreamingAssets", s_SheetContentFile);
        s_SheetListContent.Insert(0, s_SheetListContent.Count.ToString());
        File.WriteAllLines(sheetContentFile, s_SheetListContent.ToArray(), Encoding.UTF8);
        AssetDatabase.Refresh();

        // 4.Export all sheet files
        if (!Export()) {
          ExportConfig.Log("ExportClientResources.s_SheetListContent failed:");
          return false;
        }

        // 5.Export Res List
        if (!ExportRes_ResList.Export(true)) {
          ExportConfig.Log("ExportClientResources.ExportRes_ResList failed:");
          return false;
        }
      }

      ExportConfig.Log("ExportRes_Sheet.ExportClientResources Success");
      return true;
    }
    internal static bool ExportSelectedResources()
    {
      // 1.Init Environment
      if (!InitEnvironment()) {
        ExportConfig.Log("ExportSelectedResources.InitEnvironment failed:");
        return false;
      }

      // 2.Transfer Selection objects to list
      GenResInfo(true);
      List<string> diffContent = new List<string>();
      if (Selection.objects != null && Selection.objects.Length > 0) {
        foreach (UnityEngine.Object obj in Selection.objects) {
          string sheetFile = AssetDatabase.GetAssetPath(obj);
          if (sheetFile != null && !string.IsNullOrEmpty(sheetFile.Trim()) && ExportConfig.IsEndWith(sheetFile, s_SheetPattern)
           && (sheetFile.StartsWith("Assets/StreamingAssets/Client")
               || sheetFile.StartsWith("Assets/StreamingAssets/Public"))) {
            string sheetPathAdd = sheetFile.Replace("Assets/StreamingAssets", "");
            if (File.Exists(sheetFile)) {
              s_SheetListContent.Add(sheetPathAdd);
            }
          } else {
            continue;
          }
        }
      }

      // 3.Serialize sheet.txt
      if (s_SheetListContent != null && s_SheetListContent.Count > 0) {
        s_SheetData.m_IsNeedBuild = true;

        string sheetContentFile = ExportConfig.PathCombine("Assets/StreamingAssets", s_SheetContentFile);
        s_SheetListContent.Insert(0, s_SheetListContent.Count.ToString());
        File.WriteAllLines(sheetContentFile, s_SheetListContent.ToArray(), Encoding.UTF8);
        AssetDatabase.Refresh();

        // 4.Export all sheet files
        if (!Export()) {
          ExportConfig.Log("ExportSelectedResources.s_SheetListContent failed:");
          return false;
        }

        // 5.Export Res List
        if (!ExportRes_ResList.Export(true)) {
          ExportConfig.Log("ExportSelectedResources.ExportRes_ResList failed:");
          return false;
        }
      }

      ExportConfig.Log("ExportRes_Sheet.ExportSelectedResources Success");
      return true;
    }
    private static bool InitEnvironment()
    {
      ExportConfig.Log("--------------------------------------------------------------");
      ExportConfig.Log("ExportRes_Sheet Start...");

      s_SheetListContent.Clear();
      string outputPath = ExportConfig.GetPlatformPath();
      if (!System.IO.Directory.Exists(outputPath)) {
        System.IO.Directory.CreateDirectory(outputPath);
      }
      if (!System.IO.Directory.Exists(outputPath)) {
        ExportConfig.Log("InitEnvironment create output:" + outputPath);
        return false;
      }

      ExportConfig.s_ExportResDict.Clear();
      return true;
    }
    private static bool GenResInfo(bool isDiff)
    {
      Dictionary<string, ExportResInfo> tExportResDict = ExportConfig.s_ExportResDict;
      if (tExportResDict.ContainsKey(s_SheetName)) {
        ExportConfig.Log("GenResInfo sheet info exist:" + s_SheetName);
        s_SheetData = tExportResDict[s_SheetName];
        return true;
      }
      s_SheetData = new ExportResInfo();
      s_SheetData.m_Id = ExportConfig.GenNextResId();
      s_SheetData.m_AssetName = s_SheetName;
      s_SheetData.m_AssetShortName = s_SheetName;
      s_SheetData.m_PackageName = FormatSheetZipFile(isDiff);
      s_SheetData.m_MD5 = "";
      s_SheetData.m_Size = 0;
      s_SheetData.m_Guid = "";
      s_SheetData.m_DependGuid = new HashSet<string>();
      s_SheetData.m_IsNeedBuild = false;
      tExportResDict.Add(s_SheetData.m_AssetName, s_SheetData);
      return true;
    }
    private static bool Export()
    {
      List<UnityEngine.Object> targetAssets = new List<UnityEngine.Object>();
      List<string> targetAssetsNames = new List<string>();

      try {
        string sheetContentFile = ExportConfig.PathCombine("Assets/StreamingAssets", s_SheetContentFile);
        UnityEngine.TextAsset asset = AssetDatabase.LoadAssetAtPath(sheetContentFile, typeof(UnityEngine.TextAsset)) as TextAsset;
        targetAssets.Add(asset);
        targetAssetsNames.Add(s_SheetContentFile);

        // 1.Copy files to .bytes
        for (int curIndex = 1; curIndex < s_SheetListContent.Count; curIndex++) {
          string sheetFile = s_SheetListContent[curIndex];
          string sheetPathCheck = ExportConfig.PathCombine("Assets/StreamingAssets", sheetFile);
          string sheetPathCheckNew = sheetPathCheck + ".bytes";
          if (File.Exists(sheetPathCheck)) {
            File.Copy(sheetPathCheck, sheetPathCheckNew, true);
          } else {
            ExportConfig.Log("Export.sheet Copy miss:" + sheetPathCheck);
          }
        }
        AssetDatabase.Refresh();

        // 2.Add to targetAssets
        for (int curIndex = 1; curIndex < s_SheetListContent.Count; curIndex++) {
          string sheetFile = s_SheetListContent[curIndex];
          string sheetPathCheck = ExportConfig.PathCombine("Assets/StreamingAssets", sheetFile);
          string sheetPathCheckNew = sheetPathCheck + ".bytes";
          asset = AssetDatabase.LoadAssetAtPath(sheetPathCheckNew, typeof(UnityEngine.TextAsset)) as TextAsset;
          if (asset == null) {
            ExportConfig.Log("Export.sheet rename miss:" + sheetFile);
            continue;
          }
          targetAssets.Add(asset);
          targetAssetsNames.Add(sheetFile);
        }

        // 3.Build sheet assets
        UnityEngine.Object[] assets = targetAssets.ToArray();
        string[] assetNames = targetAssetsNames.ToArray();
        string resSheetZipFile = ExportConfig.GetTargetPath(s_SheetData);
        string pDir = Path.GetDirectoryName(resSheetZipFile);
        if (!Directory.Exists(pDir)) {
          Directory.CreateDirectory(pDir);
        }
        if (assets != null && assets.Length > 0) {
          BuildPipeline.BuildAssetBundleExplicitAssetNames(
            assets,
            assetNames,
            resSheetZipFile,
            ExportConfig.s_BuildOptionRes,
            ExportConfig.s_BuildOptionTarget);
          ExportConfig.Log("BuildResSheetFile Build AB:" + sheetContentFile);

          // 4.Zip sheet packages
          if (ExportConfig.s_BuildOptionZip) {
            ZipHelper.ZipFile(resSheetZipFile, resSheetZipFile);
          }
        } else {
          ExportConfig.Log("Exporte sheet package failed:" + sheetContentFile);
        }
      } catch (System.Exception ex) {
        ExportConfig.Log("ResSheetGenerator.BuildResSheetFile parse failedPath:" + ex);
        return false;
      } finally {
        // 5.Revert .bytes files
        for (int curIndex = 1; curIndex < s_SheetListContent.Count; curIndex++) {
          string sheetFile = s_SheetListContent[curIndex];
          string sheetPathCheck = ExportConfig.PathCombine("Assets/StreamingAssets", sheetFile);
          string sheetPathCheckNew = sheetPathCheck + ".bytes";
          if (File.Exists(sheetPathCheckNew)) {
            File.Delete(sheetPathCheckNew);
          }
          string sheetFileMetaNew = sheetPathCheck + ".bytes.meta";
          if (File.Exists(sheetFileMetaNew)) {
            File.Delete(sheetFileMetaNew);
          }
        }
      }

      // 6.Refresh
      AssetDatabase.Refresh();
      ExportConfig.Log("ExportRes_Sheet.Exporte Success");
      return true;
    }
    internal static string FormatSheetZipFile(bool isDiff)
    {
      return string.Format(s_ResSheetZipFormat, (isDiff ? ExportConfig.s_Version : ""));
    }

    #region Menu Item
    [MenuItem("Export/Export Selected/1.Sheet Res/Export Client Sheet", false, 31)]
    internal static void ExportClientSheet()
    {
      if (ExportConfig.Load()
        && ExportClientResources()) {
        EditorUtility.DisplayDialog(
          "Confirm",
          "ExportClientSheet Success!",
          "OK");
      } else {
        EditorUtility.DisplayDialog(
          "Confirm",
          "ExportClientSheet Failed!",
          "OK");
      }
    }
    [MenuItem("Export/Export Selected/1.Sheet Res/Export Selected Sheet", false, 32)]
    internal static void ExportSelectedSheet()
    {
      if (ExportConfig.Load()
        && ExportSelectedResources()) {
        EditorUtility.DisplayDialog(
          "Confirm",
          "ExportSelectedSheet Success!",
          "OK");
      } else {
        EditorUtility.DisplayDialog(
          "Confirm",
          "ExportSelectedSheet Failed!",
          "OK");
      }
    }
    [MenuItem("Assets/Export Selected/1.Sheet Res/Export Client Sheet", false, 31)]
    internal static void Assets_ExportClientSheet()
    {
      ExportClientSheet();
    }
    [MenuItem("Assets/Export Selected/1.Sheet Res/Export Selected Sheet", false, 32)]
    internal static void Assets_ExportSelectedSheet()
    {
      ExportSelectedSheet();
    }
    #endregion
  }
}
